package Controller;

import java.awt.Point;
import java.awt.event.KeyEvent;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.Scanner;

import Model.Game;
import Model.GameCharacter;
import Model.Maze;
import Model.Monster;
import Model.RunningBunny;
import View.ConsoleView;

/**
 * Controller that takes console input and modifies the model(Game & GameData)
 * The model then notifies the View of changes and the view reprints the maze
 * -Created Class(Feb 11,2011) Samual Martelli </pre>
 * -Modified (Mar 14th,2011)
 */
public class ConsoleGameAI implements Observer {

	// Globals to be used when moving
	public static final String UP = "UP";
	public static final String DOWN = "DOWN";
	public static final String LEFT = "LEFT";
	public static final String RIGHT = "RIGHT";

	// global variables for a monster's movements
	public static final int RANDOM_MOVE = 0;
	public static final int CHASE_MOVE = 1;
	public static final int FLEEING_MOVE = 2;

	// Global for no items check
	public static final int NO_ITEMS = 0;

	private static Game game;
	private static ConsoleView gameView;
	private static boolean gameOver;
	private int trapsLeft;
	private boolean wantToTrap;
	private static int hopsLeft;

	// based on the gametype entered generate the maze specific to the
	// game
	public ConsoleGameAI(int gameType) {
		// based on the gameType set up the right data
		// ...
		game.getData().getPlayerOfGame().addObserver(this);
		for (Monster gm : game.getData().getMonsters()) {
			gm.addObserver(this);
		}

	}

	public void keyPressed(KeyEvent gameCommand) {

		if (gameCommand.getKeyCode() == KeyEvent.VK_UP) {
		} // VK_UP is a pre-defined constant value

		else if (gameCommand.getKeyCode() == KeyEvent.VK_DOWN) {
		}

		else if (gameCommand.getKeyCode() == KeyEvent.VK_LEFT) {
		}

		else if (gameCommand.getKeyCode() == KeyEvent.VK_RIGHT) {
		}

		// new game key pressed
		else if (gameCommand.getKeyCode() == KeyEvent.VK_N) {
			newGame();
		}

		// reset game key pressed
		else if (gameCommand.getKeyCode() == KeyEvent.VK_R) {
			reset();
		}

		// exit game key pressed
		else if (gameCommand.getKeyCode() == KeyEvent.VK_E) {
			exitGame();
		}
		// Pacman game key pressed
		else if (gameCommand.getKeyCode() == KeyEvent.VK_1) {
			new ConsoleGameAI(Game.PACMAN_GAME);
		} else if (gameCommand.getKeyCode() == KeyEvent.VK_2) {
			new ConsoleGameAI(Game.MOUSE_GAME);
		} else if (gameCommand.getKeyCode() == KeyEvent.VK_3) {
			new ConsoleGameAI(Game.BUNNY_GAME);
		}
	}

	// Standard newgame for implementing game without levels
	public static void newGame() {
		gameOver = false;
	}

	// New Game implementing game with levels
	public void newGame(int level) {
		gameOver = false;

	}

	public static void exitGame() {
		gameView.displayMessage("Exiting...");
		System.exit(0);
	}

	public static void reset() {

	}

	public boolean isGameOver() {
		return gameOver;
	}

	public static void play() {

		gameView.displayMessage("Welcome to Flummox Maze Engine!");
		gameView.displayMessage("What maze game would you like to play?");
		gameView.displayMessage("Press 1 for pacman");
		gameView.displayMessage("Press 2 for mouseland");
		gameView.displayMessage("Press 3 for friskybunny");
		gameView.displayMessage("n for NewGame");
		gameView.displayMessage("r for ResetGame");
		gameView.displayMessage("e for Exit");
		gameView.displayMessage("w for UP");
		gameView.displayMessage("s for DOWN");
		gameView.displayMessage("a for LEFT");
		gameView.displayMessage("d for RIGHT");

		while (true) {
			Scanner keyControl = new Scanner(System.in);

			gameView.setLastInput((keyControl.next()));
			if (gameView.getLastInput().equals("e")) {
				exitGame();
			} else if (gameView.getLastInput().equals("r")) {
				reset();
			}

			else if (gameView.getLastInput().equals("n")) {
				newGame();
			}

			else if (gameView.getLastInput().equals("w")) {
				movePlayer(UP);
			}

			// new game key pressed
			else if (gameView.getLastInput().equals("a")) {
				movePlayer(LEFT);
			}

			// reset game key pressed
			else if (gameView.getLastInput().equals("s")) {
				movePlayer(DOWN);
			}

			// exit game key pressed
			else if (gameView.getLastInput().equals("d")) {
				movePlayer(RIGHT);
			}
			// PacMan game key pressed
			else if (gameView.getLastInput().equals("1")) {
				new ConsoleGameAI(Game.PACMAN_GAME);
			} else if (gameView.getLastInput().equals("2")) {
				new ConsoleGameAI(Game.MOUSE_GAME);
			} else if (gameView.getLastInput().equals("3")) {
				new ConsoleGameAI(Game.BUNNY_GAME);
			} else {
				// invalid input
			}
		}
	}

	/**
	 * run the game
	 */
	public static void main(String[] args) {
		// Initialises new game and calls play
		gameView = new ConsoleView();
		play();
	}

	public void setGame(Game newGame) {
		game = newGame;
	}

	public Game getGame() {
		return game;
	}

	// when the model changes the controller calls toString on Maze
	@Override
	public void update(Observable o, Object arg) {
		game.getData().printMaze();

	}

	// places a trap at cuurentSpot
	public void placeTrap(Point currentSpot) {

	}

	public int getTrapsPlaced() {
		return trapsLeft;
	}

	// gets set when player presses enter traps for GameAI
	public void setWantToTrap(boolean iWant) {
		wantToTrap = iWant;
	}

	// getHopLeft
	public int getHopsLeft() {
		return hopsLeft;
	}

	// Game will want to reset bunnies hopsLeft
	// either for new game or in-game action
	public void setHopsLeft(int newHops) {
		hopsLeft = newHops;
	}

	// checks traps for GameAI
	public boolean doesWantToTrap() {
		return wantToTrap;
	}

	// move the monster randomly
	public void moveMonster(Monster m) {
		Random numbergenerator =new Random();
		int number = numbergenerator.nextInt(3);
		Point p = null;
		p.x = m.getCoordinateX();
		p.y = m.getCoordinateY();
		if (number ==0) {
			if(canMove(m,new Point(p.x,(p.y-1)))){
				moveMonsterUp(m);
			}
		}
		else if (number ==1){
			if(canMove(m,new Point(p.x,(p.y+1)))){
				moveMonsterDown(m);
			}
		}
		else if (number ==2){
			if(canMove(m,new Point((p.x+1),p.y))){
				moveMonsterRight(m);
			}
		}
		else if (number ==3){
			if(canMove(m,new Point((p.x-1),p.y))){
				moveMonsterLeft(m);
			}
		}
	}

	public void moveMonsterLeft(Monster m){
		m.setCoordinateX(m.getCoordinateX() - 1);
	}
	public void moveMonsterRight(Monster m){
		m.setCoordinateX(m.getCoordinateX() + 1);
	}
	public void moveMonsterDown(Monster m){
		m.setCoordinateX(m.getCoordinateY() + 1);
	}
	public void moveMonsterUp(Monster m){
		m.setCoordinateX(m.getCoordinateY() - 1);
	}
	// move the monster given a specific move type
	public void moveMonster(int moveType,Monster m) {
         if (moveType== RANDOM_MOVE){
        	moveMonster(m) ;
         }
         else if (moveType== CHASE_MOVE){
        	 int x= game.getData().getPlayerOfGame().getCoordinateX();
     		int y= game.getData().getPlayerOfGame().getCoordinateY();
     		if (Math.abs(x-m.getCoordinateX())>Math.abs(y-m.getCoordinateY())){
     			if (x < m.getCoordinateX()) {
     				if(canMove(m,new Point((x-1),y))){
     					moveMonsterLeft(m);
     				}
     			}
     			else{
     				if(canMove(m,new Point((x+1),y))){
     					moveMonsterRight(m);
     				}
     			}
     		}else if (Math.abs(x-m.getCoordinateX())<=Math.abs(y-m.getCoordinateY())){
     			if (y<m.getCoordinateY()){
     				if(canMove(m,new Point(x,(y+1)))){
     					moveMonsterDown(m);
     				}
     			}
     			else {
     				if(canMove(m,new Point(x,(y-1)))){
     					moveMonsterUp(m);
     				}
     			}
     		}
          }
         else if (moveType== FLEEING_MOVE){
        	 int x= game.getData().getPlayerOfGame().getCoordinateX();
      		 int y= game.getData().getPlayerOfGame().getCoordinateY();
        	 if (Math.abs(x-m.getCoordinateX())>Math.abs(y-m.getCoordinateY())){
     			if (y<m.getCoordinateY()){
     				if(canMove(m,new Point(x,(y-1)))){
     					moveMonsterUp(m);
     				}
     			}
     			else{
     				if(canMove(m,new Point(x,(y+1)))){
     					moveMonsterDown(m);
     				}
     			}
     		}else if (Math.abs(x-m.getCoordinateX())<=Math.abs(y-m.getCoordinateY())){
     			if (x<m.getCoordinateX()){
     				if(canMove(m,new Point((x+1),y))){
     					moveMonsterRight(m);
     				}
     			}
     			else{
     				if(canMove(m,new Point((x-1),y))){
     					moveMonsterLeft(m);
     				}
     			}
     		}
          }
	}

	// allow player to hop
	public static void hopMove(Point hedgePlace, String direction) {
		if (game.getGameType() == Game.BUNNY_GAME && hopsLeft > NO_ITEMS) {
			hopsLeft--;
		}
	}

	public static void checkGameOver(Point newLocation){
		for (Monster m: game.getData().getMonsters()){
    		if (newLocation == m.getCoordinate() && !(m instanceof RunningBunny)) {
                gameOver = true;
                gameView.displayMessage("You've been killed! Game Over");
            } else if (newLocation == m.getCoordinate()){
            	gameOver= true;
            	gameView.displayMessage("You've caught the bunny! Game Over");
            }
		}
           if(game.getGameType() == Game.MOUSE_GAME){
            	if(newLocation==game.getData().getGameMaze().EXIT)   {
            		gameOver= true;
                	gameView.displayMessage("You've escaped! Game Over");
            	}
           }
           else if(game.getGameType() == Game.PACMAN_GAME){
           	  //MazeMap<Point,Integer> map = game.getData().getGameMaze().getGameMap();
           	  int dotsLeft = 0;
           	  for(int i = 0; i < Maze.MAP_SIZE;i++){
           		for(int j = 0; j < Maze.MAP_SIZE;j++){
             		  Point p = new Point(i,j);
             		 // if (map.get(p) == Maze.ITEM_SPACE){
             			//  dotsLeft+=1;
             		  //}
           		}
           	  }
           		//if (dotsLeft == 0){
           		//	gameOver= true;
                //	gameView.displayMessage("You've eaten all dots! Game Over");
           		//}
           	  }
           	  
	}
	//move player in a direction
	public static void movePlayer(String direction){
		if (direction == UP && canMove(game.getData().getPlayerOfGame(),game.getData().getPlayerOfGame().getCoordinate())&& !gameOver){
			//might hop here
			int x=game.getData().getPlayerOfGame().getCoordinateX();
			int y=game.getData().getPlayerOfGame().getCoordinateY(); 
			Point p = new Point(x,(y-1));
			if(game.getGameType() == Game.BUNNY_GAME){
				//if(game.getData().getGameMaze().getGameMap().get(p) == Maze.HEDGE_SPACE){
				//	hopMove(p,direction);
				//}
	         }
			checkGameOver(p);
			game.getData().getPlayerOfGame().setCoordinateY(y-1);
				
		}
		
		else if (direction == DOWN && canMove(game.getData().getPlayerOfGame(),game.getData().getPlayerOfGame().getCoordinate())&& !gameOver){
			
			int x=game.getData().getPlayerOfGame().getCoordinateX();
			int y=game.getData().getPlayerOfGame().getCoordinateY(); 
			Point p = new Point(x,(y+1));
			if(game.getGameType() == Game.BUNNY_GAME){
				//if(game.getData().getGameMaze().getGameMap().get(p) == Maze.HEDGE_SPACE){
				//	hopMove(p,direction);
				//}
			}
			checkGameOver(p);
			game.getData().getPlayerOfGame().setCoordinateY(y+1);
		}
		else if (direction == RIGHT && canMove(game.getData().getPlayerOfGame(),game.getData().getPlayerOfGame().getCoordinate())&& !gameOver){
			int x=game.getData().getPlayerOfGame().getCoordinateX();
			int y=game.getData().getPlayerOfGame().getCoordinateY(); 
			Point p = new Point((x+1),y);
			if(game.getGameType() == Game.BUNNY_GAME){
				//if(game.getData().getGameMaze().getGameMap().get(p) == Maze.HEDGE_SPACE){
				//	hopMove(p,direction);
				//}
				
			}
			checkGameOver(p);
			game.getData().getPlayerOfGame().setCoordinateX(x+1);
	
		}
		else if (direction == LEFT && canMove(game.getData().getPlayerOfGame(),game.getData().getPlayerOfGame().getCoordinate())&& !gameOver){
			int x=game.getData().getPlayerOfGame().getCoordinateX();
			int y=game.getData().getPlayerOfGame().getCoordinateY(); 
			Point p = new Point((x+1),y);
			//if(game.getGameType() == Game.BUNNY_GAME){
				//if(game.getData().getGameMaze().getGameMap().get(p) == Maze.HEDGE_SPACE){
				//	hopMove(p,direction);
				//}
				
			//}
			checkGameOver(p);
			game.getData().getPlayerOfGame().setCoordinateX(x-1);
			
	
		}
}
	

	// MoveAction varies depending on the game
	public void moveAction(int gameType, Point location) {
		if (gameType == Game.MOUSE_GAME && doesWantToTrap()
				&& trapsLeft > NO_ITEMS) {
			placeTrap(location);
			game.getData().getGameMaze().setMazeItem(location,Maze.TRAP_SPACE);
			trapsLeft--;
			setWantToTrap(false);
		}

	}

	// go through the map counting the number of item spaces
	// Note: character spaces are assumed to have already used the item on them
	public void getItemsLeft() {

	}

	// check if a player can move
	public static boolean canMove(GameCharacter gamecharacter, Point p) {
		int mazeitem = game.getData().getGameMaze().getMazeItem(p);
		// returns true if and only if mazeItem is not a wall and point is on
		// the map
		return (mazeitem != game.getData().getGameMaze().WALL_SPACE);
				//&& game.getData().getGameMaze().getGameMap().containsKey(p);

	}

}
